package bfw3b9.atprin.Interface;

import java.nio.IntBuffer;

import android.opengl.GLES20;
import android.util.Log;

/**
 * Laden und Verwalten der Shader
 * 
 * @author Thomas Rinsch
 *
 * Quelle: http://www.learnopengles.com/android-lesson-one-getting-started/
 */
public class Shader {

	private final static String LOGTAG = "Shader";
	
	// Vertex-Shader zum Anzeigen
	public static final String DISPLAY_VERTEX_SHADER_CODE = 
						"uniform mat4 u_MVPMatrix;      \n"		
					+	"attribute vec4 a_Position;     \n"	
					+	"attribute vec2 a_TexCoordinate;\n"	// Per-Vertex Texturkoordinate
					+ "varying vec2 v_TexCoordinate;  \n" // Wird an den Fragment-Shader uebergeben
					+ "void main()                    \n"
					+ "{                              \n"
					+ "   v_TexCoordinate = a_TexCoordinate; \n"	// Uebergabe der Texturkoordinaten an den Fragment-Shader
					+ "   gl_Position = u_MVPMatrix   \n"
					+ "               * a_Position;   \n"
					+ "}                              \n";

	// Fragment-Shader zum Anzeigen
	public static final String DISPLAY_FRAGMENT_SHADER_CODE = 			
			          "precision mediump float;  \n" 
					+ "uniform sampler2D u_Texture; \n" 	// Eingabetextur
					+ "varying vec2 v_TexCoordinate;" 		// Interpolierte per-Fragment Texturkoordinate
					+ "void main(){ \n" 
					+ " gl_FragColor = (texture2D(u_Texture, v_TexCoordinate)); \n" 	// Textur hinzufuegen
					+ "} \n";


	// Vertex-Shader zum Anzeigen
	public static final String IDENT_VERTEX_SHADER_CODE = 
			  "uniform mat4 u_MVPMatrix;      \n"     // A constant representing the combined model/view/projection matrix.
			+ "uniform float a_Identity; 	  \n"
			+ "attribute vec4 a_Position;     \n"
			+ "attribute vec2 a_TexCoordinate;\n"		// Muss mit rein genommen werden, weil es Einfluss auf die Groesse der Darstellung hat. Keine Ahnung warum
			+ "void main()                    \n"
			+ "{                              \n"
			+ "   gl_Position = u_MVPMatrix   \n"
			+ "               * a_Position;   \n"
			+ "}                              \n";

	// Fragment-Shader zum Anzeigen
	public static final String IDENT_FRAGMENT_SHADER_CODE = 
			  "precision mediump float;  \n"
			+ "uniform float a_Identity;     \n"
			+ "void main()                    \n"   
			+ "{                              \n"
			+ "   gl_FragColor = vec4 (a_Identity, a_Identity, a_Identity, 1.0);     \n"   
			+ "}              				  \n";

	/**
	 * Laedt die Shader zum Anzeigen der Texturen
	 * @return
	 */
	public static int initShader(String _vertexShaderCode, String _fragmentShaderCode)
	{
		Log.d(LOGTAG, "Lade Shader");
		/*
		 * Shader laden und an das OpenGL-Programm anhaengen
		 */
		int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,_vertexShaderCode);
		int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,_fragmentShaderCode);

		// leeres OpenGL-Programm erzeugen
		int program = GLES20.glCreateProgram();

		// Die Shader an das Programm anhaengen
		GLES20.glAttachShader(program,vertexShader);
		GLES20.glAttachShader(program,fragmentShader);

		// Die Shader im Programm verlinken (ausfuehrbar machen)
		GLES20.glLinkProgram(program);
		
		// Debugging: Feststellen, ob der Shader erfolgreich gebunden wurde
		IntBuffer buffer = IntBuffer.allocate(1);
		GLES20.glGetProgramiv( program, GLES20.GL_LINK_STATUS,  buffer);
		if(buffer.get(0)==0)
		{
			Log.e(LOGTAG, "Fehler beim Linken von einem Shader. \n " + 
					"Vertex Shader Code: " + _vertexShaderCode + " \n " +
					"Fragment Shader Code: " + _fragmentShaderCode);
		}else
		{
			Log.d(LOGTAG, "Shader erfolgreich geladen");
		}
		return program;
	}


	/**
	 * Laedt die Shader und laesst sie kompilieren
	 * @param type	Shadertyp: GLES20.GL_VERTEX_SHADER oder GLES20.GL_FRAGMENT_SHADER
	 * @param shaderCode	Der eigentliche Shadercode
	 * @return	Die Shader-ID, ueber die auf diesen Shader zugegriffen werden kann
	 */
	private static int loadShader(int type, String shaderCode)
	{
		Log.d(LOGTAG, "Kompiliere Shader");
		
		// leeren Shader erzeugen
		int shader = GLES20.glCreateShader(type);

		// Shadercode zum erzeugten Shader hinzufuegen
		GLES20.glShaderSource(shader, shaderCode);

		// Shader kompilieren
		GLES20.glCompileShader(shader);

		// Debugging: Feststellen, ob der Shader erfolgreich compiled wurde
				IntBuffer buffer = IntBuffer.allocate(1);
				GLES20.glGetShaderiv( shader, GLES20.GL_COMPILE_STATUS,  buffer);
				if(buffer.get(0)==0)
				{
					Log.e(LOGTAG, "Fehler beim compilen von einem Shader. \n " + 
							"Shader Code: " + shaderCode );
				}
				else
				{
					Log.d(LOGTAG, "Shader erfolgreich kompiliert");
				}
		return shader;
	}

}
